<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">

    <meta name="viewport"
        content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height" />

    <title>PDF Viewer</title>

    <link rel="shortcut icon"
        href="" />

    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.3/css/bulma.min.css">

    <script src="pdfium.js?v={pdfium-branch}"></script>

    <script>
        // variables
        let currentPageIndex = 1;
        let pageLoaded = false;
        let moduleLoaded = false;
        let debugMode = false;
        let autoOpenMode = true;

        // pdfium initialization
        let FPDF = {};

        Object.assign(FPDF, {
            ANNOT: 0x01, // Set if annotations are to be rendered.
            LCD_TEXT: 0x02, // Set if using text rendering optimized for LCD display.
            NO_NATIVETEXT: 0x04, // Don't use the native text output available on some platforms
            GRAYSCALE: 0x08, // Grayscale output.
            DEBUG_INFO: 0x80, // Set if you want to get some debug info. Please discuss with Foxit first if you need to collect debug info.
            NO_CATCH: 0x100, // Set if you don't want to catch exception.
            RENDER_LIMITEDIMAGECACHE: 0x200, // Limit image cache size.
            RENDER_FORCEHALFTONE: 0x400, // Always use halftone for image stretching.
            PRINTING: 0x800, // Render for printing.
            REVERSE_BYTE_ORDER: 0x10, // Set whether render in a reverse Byte order, this flag only.
            Bitmap_Gray: 1,
            Bitmap_BGR: 2,
            Bitmap_BGRx: 3,
            Bitmap_BGRA: 4,
            LAST_ERROR: { // Last error types
                SUCCESS: 0,
                UNKNOWN: 1,
                FILE: 2,
                FORMAT: 3,
                PASSWORD: 4,
                SECURITY: 5,
                PAGE: 6
            }
        });

        const I8 = Int8Array;
        const I16 = Int16Array;
        const I32 = Int32Array;
        const U8 = Uint8Array;
        const CH = U8;
        const U16 = Uint16Array;
        const U32 = Uint32Array;
        const F32 = Float32Array;
        const F64 = Float64Array;

        const H = (t, s, d) => f => {
            const [m, ...a] = heap(t, s);
            const v = f(...a.map(x => x.p));

            if (!v) {
                m.free();
                return d;
            }

            const r = a.map(x => x.v);
            m.free();
            return r;
        };

        const F = FPDF.Bitmap_BGRA;
        const C = 4;

        // runtime initialized
        Module.onRuntimeInitialized = async _ => {
            moduleLoaded = true;

            if (pageLoaded) {
                console.log('The module was loaded!');
            }

            checkIfEverythingWasLoaded();
        };

        // functions
        async function loadFile() {
            try {
                changeButton('Loading file from input...', 'warning');

                resetOnLoad();

                let files = fileInput.files;

                if (files.length <= 0) {
                    throw { message: "Select a PDF file or type a public PDF url" };
                }

                let file = files[0];

                let fileByteArray = await fileToByteArray(file);

                if (fileByteArray.length <= 0) {
                    throw { message: "The PDF file is invalid" };
                }

                changeButton('Processing file...', 'warning');

                setTimeout(function () {
                    processPDF(fileByteArray);
                }, 300);
            } catch (error) {
                changeButton('Error while load file', 'danger');
                console.log('Error while load file: ' + error.message);
            }
        }

        async function loadFileFromURL(url) {
            try {
                changeButton('Loading file from URL...', 'warning');

                resetOnLoad();

                let response = await fetch(url);
                let fileBuffer = await response.arrayBuffer();
                let fileByteArray = new Uint8Array(fileBuffer);

                if (fileByteArray.length <= 0) {
                    throw { message: "The PDF file is invalid" };
                }

                changeButton('Processing file...', 'warning');

                setTimeout(function () {
                    processPDF(fileByteArray);
                }, 300);
            } catch (error) {
                changeButton('Error while load file from URL', 'danger');
                console.log('Error while load file from URL: ' + error.message);
            }
        }

        async function processPDF(fileByteArray) {
            try {
                // html general
                changeButton('Processing file...', 'warning');

                let pageListContainer = document.getElementById('pageListContainer');
                let pageList = document.getElementById('pageList');
                let pageListTitle = document.getElementById('pageListTitle');

                pageListContainer.style.display = "none";
                pageList.innerHTML = "";

                // check file size
                console.log('Getting file size...');

                let fileSize = fileByteArray.length;
                console.log("File size: " + fileSize + " bytes");

                // init library
                console.log('Initializing library...');

                FPDF.Init();

                // load document to memory
                console.log('Loading data to buffer...');

                let wasmBuffer = Module._malloc(fileSize);
                Module.HEAPU8.set(fileByteArray, wasmBuffer);

                // create document
                console.log('Loading document...');

                let o = {
                    wasm: FPDF.LoadMemDocument(wasmBuffer, fileSize, "")
                };

                o.getPageSize = (i = 0, s = 2) => H(F64, 2, [-1, -1])((w, h) => FPDF.GetPageSizeByIndex(o.wasm, i, w, h)).map(v => parseInt(v) * s);

                o.getRender = function (i = 0, w, h) {
                    const flag = FPDF.REVERSE_BYTE_ORDER | FPDF.ANNOT;
                    const heap = Module._malloc(w * h * C);

                    for (let i = 0; i < w * h * C; i++) {
                        Module.HEAPU8[heap + i] = 0;
                    }

                    const bmap = FPDF.Bitmap_CreateEx(w, h, F, heap, w * C);
                    const page = FPDF.LoadPage(this.wasm, i);

                    FPDF.Bitmap_FillRect(bmap, 0, 0, w, h, 0xFFFFFFFF);
                    FPDF.RenderPageBitmap(bmap, page, 0, 0, w, h, 0, flag);
                    FPDF.Bitmap_Destroy(bmap);
                    FPDF.ClosePage(page);

                    return heap;
                };

                o.getPageRender = function (n = 0, w, h) {
                    let pageRenderPtr = this.getRender(n, w, h);
                    let pageRenderData = [];

                    for (let v = 0; v < w * h * C; v++) {
                        pageRenderData.push(Module.HEAPU8[pageRenderPtr + v]);
                    }

                    Module._free(pageRenderPtr);

                    return pageRenderData;
                };

                o.render = function (n = 0, canvas, scale, rotation) {
                    const [w, h] = this.getPageSize(n, scale, rotation);
                    const data = this.getPageRender(n, w, h, rotation);

                    canvas.width = w;
                    canvas.height = h;

                    const x = canvas.getContext('2d');
                    const i = x.createImageData(w, h);
                    i.data.set(data);
                    x.putImageData(i, 0, 0);
                };

                o.getLastError = function () {
                    let lastError = FPDF.GetLastError();

                    switch (lastError) {
                        case FPDF.LAST_ERROR.SUCCESS:
                            return "success";
                            break;
                        case FPDF.LAST_ERROR.UNKNOWN:
                            return "unknown error";
                            break;
                        case FPDF.LAST_ERROR.FILE:
                            return "file not found or could not be opened";
                            break;
                        case FPDF.LAST_ERROR.FORMAT:
                            return "file not in PDF format or corrupted";
                            break;
                        case FPDF.LAST_ERROR.PASSWORD:
                            return "password required or incorrect password";
                            break;
                        case FPDF.LAST_ERROR.SECURITY:
                            return "unsupported security scheme";
                            break;
                        case FPDF.LAST_ERROR.PAGE:
                            return "page not found or content error";
                            break;
                        default:
                            return "unknown error";
                    }
                }

                // check last error
                let lastError = o.getLastError();
                console.log("Load document state: " + lastError);

                // count page
                console.log('Couting pages...');

                let pages = FPDF.GetPageCount(o.wasm);
                console.log('Pages: ' + pages);

                // list all pages
                if (pages > 0) {
                    console.log('Rendering ' + pages + ' PDF pages...');

                    for (let x = 0; x < pages; x++) {
                        console.log('Rendering page ' + (x + 1) + '...');

                        // render to canvas
                        console.log("Rendering to canvas...");

                        let canvas = document.createElement('canvas');

                        o.render(x, canvas, 3.0, 90);

                        let dataUri = canvas.toDataURL();

                        pageRenderData = null;
                        canvas = null;
                        ctx = null;
                        idata = null;

                        // add page item
                        console.log("Adding page item...");

                        let image = document.createElement('img');
                        image.id = "pageImage" + (x + 1);
                        image.src = dataUri;
                        image.className = "page-list-item";
                        image.onclick = function () {
                            openModal();
                            changeCurrentPageItem(x + 1);
                        };

                        let content = document.createElement('div');
                        content.className = "content";
                        content.appendChild(image);

                        let cardContent = document.createElement('div');
                        cardContent.className = "card-content";
                        cardContent.appendChild(content);

                        let card = document.createElement('div');
                        card.className = "card";
                        card.appendChild(cardContent);

                        let column = document.createElement('div');
                        column.className = "column is-half-mobile is-one-third-tablet is-one-third-desktop is-one-third-widescreen is-one-quarter-fullhd";
                        column.appendChild(card);

                        pageList.appendChild(column);

                        // show results
                        console.log('Page ' + (x + 1) + ' rendered');
                    }

                    pageListTitle.innerHTML = "Number of pages: " + pages;

                    pageListContainer.style.display = "block";

                    if (autoOpenMode) {
                        showPageItem(currentPageIndex);
                    }

                    showFileForm(false);

                    setTimeout(function () {
                        console.log('Scrolling to top...');
                        scrollToTop();
                    }, 100);
                } else {
                    console.log('Cannot render PDF pages: PDF is empty');
                }

                // clean memory
                console.log('Cleaning objects...');

                Module._free(wasmBuffer);

                FPDF.CloseDocument(o.wasm);
                FPDF.DestroyLibrary();

                // initial state
                buttonToInitialState();

                console.log('Finished');
            } catch (error) {
                changeButton('Error while process PDF', 'danger');
                console.log('Error while process PDF: ' + error.message);
            }
        }

        function fileToByteArray(file) {
            return new Promise((resolve, reject) => {
                try {
                    let reader = new FileReader();
                    let fileByteArray = [];

                    reader.readAsArrayBuffer(file);
                    reader.onloadend = (evt) => {
                        if (evt.target.readyState == FileReader.DONE) {
                            let arrayBuffer = evt.target.result,
                                array = new Uint8Array(arrayBuffer);
                            for (byte of array) {
                                fileByteArray.push(byte);
                            }
                        }
                        resolve(fileByteArray);
                    }
                }
                catch (e) {
                    reject(e);
                }
            })
        }

        function changeButton(text, className) {
            let btRun = document.getElementById('btRun');
            btRun.firstChild.data = text;
            btRun.className = 'button is-' + className;
        }

        function getUrlParam(param) {
            let params = getAllUrlParams(window.location.href);

            if (params != null && params !== undefined) {
                if (params.hasOwnProperty(param)) {
                    let value = params[param];

                    if (value != null && value !== undefined) {
                        return value;
                    }
                }
            }

            return null;
        }

        function getAllUrlParams(url) {
            // get query string from url (optional) or window
            var queryString = url ? url.split('?')[1] : window.location.search.slice(1);

            // we'll store the parameters here
            var obj = {};

            // if query string exists
            if (queryString) {

                // stuff after # is not part of query string, so get rid of it
                queryString = queryString.split('#')[0];

                // split our query string into its component parts
                var arr = queryString.split('&');

                for (var i = 0; i < arr.length; i++) {
                    // separate the keys and the values
                    var a = arr[i].split('=');

                    // in case params look like: list[]=thing1&list[]=thing2
                    var paramNum = undefined;
                    var paramName = a[0].replace(/\[\d*\]/, function (v) {
                        paramNum = v.slice(1, -1);
                        return '';
                    });

                    // set parameter value (use 'true' if empty)
                    var paramValue = typeof (a[1]) === 'undefined' ? true : a[1];

                    // if parameter name already exists
                    if (obj[paramName]) {
                        // convert value to array (if still string)
                        if (typeof obj[paramName] === 'string') {
                            obj[paramName] = [obj[paramName]];
                        }
                        // if no array index number specified...
                        if (typeof paramNum === 'undefined') {
                            // put the value on the end of the array
                            obj[paramName].push(paramValue);
                        }
                        // if array index number specified...
                        else {
                            // put the value at that index number
                            obj[paramName][paramNum] = paramValue;
                        }
                    }
                    // if param name doesn't exist yet, set it
                    else {
                        obj[paramName] = paramValue;
                    }
                }
            }

            return obj;
        }

        function buttonToInitialState() {
            changeButton('Process file', 'success');
        }

        function changeFileTitle(title) {
            let fileTitle = document.getElementById('fileTitle');
            fileTitle.innerHTML = decodeURI(title);
        }

        function changePageTitle(title) {
            document.title = decodeURI(title) + " - PDF Viewer";
        }

        function showDebugConsole(show) {
            let debugConsole = document.getElementById('debugConsole');

            if (show) {
                debugConsole.style.display = "block";
            } else {
                debugConsole.style.display = "none";
            }
        }

        function showFileTitle(show) {
            let fileTitle = document.getElementById('fileTitle');

            if (show) {
                fileTitle.style.display = "block";
            } else {
                fileTitle.style.display = "none";
            }
        }

        function showFileForm(show) {
            let fileForm = document.getElementById('fileForm');

            if (show) {
                fileForm.style.display = "block";
            } else {
                fileForm.style.display = "none";
            }
        }

        function showLoading(show) {
            let loading = document.getElementById('loadingContainer');

            if (show) {
                loading.className = "loader-wrapper is-active";
            } else {
                loading.className = "loader-wrapper";
            }

            return false;
        }

        function showFooter(show) {
            let footer = document.getElementById('footer');

            if (show) {
                footer.style.display = "block";
            } else {
                footer.style.display = "none";
            }
        }

        function scrollToTop() {
            window.scrollTo({ top: 0 })
        }

        function openModal() {
            let modal = document.getElementById('pageModal');

            if (typeof modal != "undefined") {
                modal.className = "modal is-active";
            }
        }

        function closeModal() {
            let modal = document.getElementById('pageModal');

            if (typeof modal != "undefined") {
                modal.className = "modal";
            }
        }

        function modalIsOpened() {
            let modal = document.getElementById('pageModal');

            if (modal.classList.contains("is-active")) {
                return true;
            }

            return false;
        }

        function changeCurrentPageItemPlus(n) {
            showPageItem(currentPageIndex += n);
        }

        function changeCurrentPageItem(index) {
            showPageItem(index);
        }

        function showPageItem(index) {
            let pages = document.getElementsByClassName("page-list-item");
            let pageModalImage = document.getElementById("pageModalImage");

            if (index > pages.length) {
                currentPageIndex = pages.length;
            } else if (index < 1) {
                currentPageIndex = 1;
            } else {
                currentPageIndex = index;
            }

            let page = pages[currentPageIndex - 1];

            if (typeof page != "undefined") {
                pageModalImage.src = page.src;
            }

            openModal();
        }

        function resetOnLoad() {
            currentPageIndex = 1;
        }

        function bindKeys() {
            document.onkeydown = function (e) {
                switch (e.which) {
                    case 27:
                        // esc
                        if (modalIsOpened()) {
                            closeModal();
                            e.preventDefault();
                        }

                        break;

                    case 37:
                        // left
                        if (modalIsOpened()) {
                            changeCurrentPageItemPlus(-1)
                            e.preventDefault();
                        }

                        break;

                    case 39:
                        // right
                        if (modalIsOpened()) {
                            changeCurrentPageItemPlus(1)
                            e.preventDefault();
                        }

                        break;

                    default: return;
                }
            };
        }

        function checkIfEverythingWasLoaded() {
            if (pageLoaded && moduleLoaded) {
                startApp();
            }
        }

        function startUI() {
            // change console methods
            if (typeof console != "undefined") {
                if (typeof console.log != 'undefined') {
                    console.olog = console.log;
                } else {
                    console.olog = function () { };
                }
            }

            console.log = function (message) {
                // we will disable it for now
                // console.olog(message);

                var currentDate = new Date().toLocaleTimeString();

                var e = document.createElement('p');
                e.innerHTML = "➔ [" + currentDate + "] " + message;

                document.getElementById('debugConsoleContent').prepend(e);
            };

            console.error = console.debug = console.info = console.log;

            // check for wasm support
            if (!('WebAssembly' in window)) {
                console.log('You need a browser with Web Assembly support enabled :(');
                changeButton('Web Assembly not supported', 'danger');
                return;
            }

            // file input
            var fileInput = document.querySelector('#file-container input[type=file]');
            fileInput.onchange = () => {
                if (fileInput.files.length > 0) {
                    var fileName = document.querySelector('#file-container .file-name');
                    fileName.textContent = fileInput.files[0].name;
                }
            }

            // initial state
            bindKeys();
            buttonToInitialState();
        }

        function initializeFPDF() {
            FPDF.Init = Module.cwrap('PDFium_Init');
            FPDF.RenderPageBitmap = Module.cwrap('FPDF_RenderPageBitmap', '', ['number', 'number', 'number', 'number', 'number', 'number', 'number', 'number']);

            FPDF.Bitmap_FillRect = Module.cwrap('FPDFBitmap_FillRect', '', ['number', 'number', 'number', 'number', 'number', 'number']);
            FPDF.Bitmap_CreateEx = Module.cwrap('FPDFBitmap_CreateEx', 'number', ['number', 'number', 'number', 'number', 'number']);
            FPDF.Bitmap_Destroy = Module.cwrap('FPDFBitmap_Destroy', '', ['number']);

            FPDF.LoadPage = Module.cwrap('FPDF_LoadPage', 'number', ['number', 'number']);
            FPDF.ClosePage = Module.cwrap('FPDF_ClosePage', '', ['number']);

            FPDF.LoadMemDocument = Module.cwrap('FPDF_LoadMemDocument', 'number', ['number', 'number', 'string']);
            FPDF.GetPageSizeByIndex = Module.cwrap('FPDF_GetPageSizeByIndex', 'number', ['number', 'number', 'number', 'number']);
            FPDF.GetLastError = Module.cwrap('FPDF_GetLastError', 'number');
            FPDF.GetPageCount = Module.cwrap('FPDF_GetPageCount', 'number', ['number']);
            FPDF.CloseDocument = Module.cwrap('FPDF_CloseDocument', '', ['number']);
            FPDF.DestroyLibrary = Module.cwrap('FPDF_DestroyLibrary');

            window.heap = (J, s) => {
                let E;
                switch (J) {
                    case Int8Array: E = Module.HEAP8; break;
                    case Int16Array: E = Module.HEAP16; break;
                    case Int32Array: E = Module.HEAP32; break;
                    case Uint8Array: E = Module.HEAPU8; break;
                    case Uint16Array: E = Module.HEAPU16; break;
                    case Uint32Array: E = Module.HEAPU32; break;
                    case Float32Array: E = Module.HEAPF32; break;
                    case Float64Array: E = Module.HEAPF64; break;
                }
                const Z = J.BYTES_PER_ELEMENT; const m = Module._malloc(s * Z);
                const a = Array(1 + s); a[0] = ({ s, J, Z, E, m, free: () => Module._free(m) });
                for (let i = 0; i < s; i++) a[i + 1] = ({ p: m + (i * Z), get v() { return E[m / Z + i]; } });
                return a;
            };
        }

        function startApp() {
            // initialize FPDF
            initializeFPDF();

            // let button start load files
            let btRun = document.getElementById('btRun');
            btRun.onclick = function () {
                let urlInput = document.getElementById('urlInput');
                let url = urlInput.value;

                if (url.length > 0) {
                    loadFileFromURL(url);
                } else {
                    loadFile();
                }
            }

            // load data from url
            let urlParamTitle = getUrlParam("title");
            let urlParamUrl = getUrlParam("url");
            let urlParamDebug = getUrlParam("debug");
            let urlParamOpen = getUrlParam("open");

            if (urlParamDebug && urlParamDebug === "1") {
                debugMode = true;
            } else {
                debugMode = false;
            }

            if (urlParamOpen && urlParamOpen === "0") {
                autoOpenMode = false;
            } else {
                autoOpenMode = true;
            }

            if (urlParamTitle) {
                changeFileTitle(urlParamTitle);
                changePageTitle(urlParamTitle);
            }

            if (urlParamUrl) {
                let urlInput = document.getElementById('urlInput');
                urlParamUrl.value = urlParamUrl;

                loadFileFromURL(decodeURI(urlParamUrl));
            }

            // show inicial things
            showDebugConsole(debugMode);
            showFileTitle(true);
            showFileForm(true);
            showFooter(true);

            setTimeout(function () {
                showLoading(false);
            }, 500);
        }

        window.onload = function (e) {
            pageLoaded = true;

            startUI();

            console.log('The page was loaded!');

            checkIfEverythingWasLoaded();
        }
    </script>

    <style>
        /* general */
        body {
            touch-action: pan-x pan-y;
            display: flex;
            min-height: 100vh;
            flex-direction: column;
        }

        .section {
            flex: 1;
        }

        .footer {
            padding-bottom: 1.5rem;
            padding-top: 1.5rem;
            display: none;
        }

        /* page list item */
        .page-list-item {
            box-sizing: border-box;
            display: flex;
            justify-content: center;
            padding: 2px;
            cursor: pointer;
        }

        .page-list-item img {
            max-width: 70%;
        }

        /* modal */
        .modal {
            display: none;
            position: fixed;
            z-index: 1;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.5);
        }

        .modal-content {
            max-height: none !important;
            overflow: hidden;
            width: 78%;
            text-align: center;
        }

        /* next & previous buttons */
        .page-prev,
        .page-next {
            cursor: pointer;
            position: absolute;
            top: 50%;
            width: auto;
            padding: 16px;
            margin-top: -34px;
            color: white;
            font-weight: bold;
            font-size: 20px;
            transition: 0.6s ease;
            border-radius: 0 3px 3px 0;
            user-select: none;
            -webkit-user-select: none;
        }

        .page-next {
            right: 0;
            border-radius: 3px 0 0 3px;
        }

        .page-prev {
            left: 0;
            border-radius: 3px 0 0 3px;
        }

        /* page list */
        #pageList .card-content {
            padding: 0;
        }

        /*  modal */
        .modal-close {
            margin-right: -12px;
        }

        /* page list container */
        #pageListContainer {
            margin-bottom: 30px;
            display: none;
        }

        /* page title */
        #pageListTitle {
            margin-bottom: 24px;
            font-weight: bold;
        }

        /* page modal image */
        #pageModalImage {
            max-height: 100%;
        }

        /* loader */
        .loader-wrapper {
            position: absolute;
            top: 0;
            left: 0;
            height: 100%;
            width: 100%;
            background: #fff;
            opacity: 0;
            z-index: -1;
            transition: opacity .3s;
            display: flex;
            justify-content: center;
            align-items: center;
            border-radius: 6px;
        }

        .loader {
            height: 80px;
            width: 80px;
            margin: 0 auto;
        }

        .is-active {
            opacity: 1;
            z-index: 1;
        }

        /* file title */
        #fileTitle {
            display: none;
        }

        /* file form */
        #fileForm {
            display: none;
        }
    </style>
</head>

<body>
    <!-- loading -->
    <div id="loadingContainer">
        <div class="loader-wrapper is-active">
            <div class="loader is-loading"></div>
        </div>
    </div>

    <!-- content -->
    <section class="section is-centered">
        <div class="container">

            <!-- title -->
            <h1 id="fileTitle" class="title" style="display: none;">PDF Viewer</h1>

            <div id="fileForm" style="display: none;">
                <br>
                <p>1 - Select your PDF file:</p>
                <br>

                <!-- file input -->
                <div id="file-container" class="file is-info has-name is-boxed">
                    <label class="file-label">
                        <input class="file-input" id="fileInput" type="file" accept="application/pdf">
                        <span class="file-cta">
                            <span class="file-label">
                                Choose a file…
                            </span>
                        </span>
                        <span class="file-name">
                            No file uploaded
                        </span>
                    </label>
                </div>
                <br>
                <br>

                <!-- url input -->
                <p>Or type any PDF public url:</p>
                <br>
                <input class="input" type="text" placeholder="" id="urlInput">
                <br>
                <br>

                <!-- process button -->
                <p>2 - Press button to process:</p>
                <br>
                <button class="button is-warning" id="btRun">Loading...</button>
                <br>
                <br>
                <br>
            </div>

            <!-- page list container -->
            <div id="pageListContainer" style="display: none;">
                <p style="font-weight: bold;" id="pageListTitle">Number of pages: 0</p>

                <!-- page as a column -->
                <div class="columns is-multiline is-mobile" id="pageList"></div>

                <div class="modal" id="pageModal">
                    <div class="modal-background" onclick="closeModal()"></div>
                    <div class="modal-content">
                        <img id="pageModalImage" src="">
                    </div>

                    <!-- modal buttons -->
                    <a class="page-prev" onclick="changeCurrentPageItemPlus(-1)">&#10094;</a>

                    <a class="page-next" onclick="changeCurrentPageItemPlus(1)">&#10095;</a>

                    <button onclick="closeModal()" class="modal-close is-large" aria-label="close"></button>
                </div>
            </div>

            <!-- debug console -->
            <div class="card" id="debugConsole" style="display: none;">
                <header class="card-header">
                    <p class="card-header-title">
                        Debug console
                    </p>
                </header>
                <div class="card-content">
                    <div class="content">
                        <div id="debugConsoleContent">
                            <p>➔ Debug messages will be showed here</p>
                        </div>
                    </div>
                </div>
            </div>
        </div>

    </section>

    <!-- footer -->
    <footer id="footer" class="footer" style="display: none;">
        <div class="content has-text-centered">
            <p>
                This application is powered by an open source project called PDF Viewer and can be found <a
                    target="_blank" href="https://github.com/paulo-coutinho/pdfium-lib">here</a>. No data is stored and
                everything run only on client side.
            </p>
            <p>
                PDFium branch "{pdfium-branch}" and commit "{pdfium-commit}".
            </p>
        </div>
    </footer>

    <!-- google analytics -->
    <script async src="https://www.googletagmanager.com/gtag/js?id=G-J2FWK7KZMQ"></script>
    <script>
        window.dataLayer = window.dataLayer || [];
        function gtag() { dataLayer.push(arguments); }
        gtag('js', new Date());

        gtag('config', 'G-J2FWK7KZMQ');
    </script>
</body>

</html>
